﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using GraphSharp.Controls;
using SuffixTreeView.Graph;
using Algorithms.FSharp;

namespace SuffixTreeView.ViewModel
{
    /// <summary>
    /// The View Model 
    /// </summary>
    class GraphViewModel : INotifyPropertyChanged 
    {
        SuffixTreeGraph _graph = null;
        private List<String> _layoutAlgorithmTypes = new List<string>();
        private string _layoutAlgorithmType;
        Dictionary<int, SuffixTreeNode> _existingNodes = new Dictionary<int, SuffixTreeNode>();
        string _text;

        public GraphViewModel()
        {
            //Add Layout Algorithm Types
            _layoutAlgorithmTypes.Add("BoundedFR");
            _layoutAlgorithmTypes.Add("Circular");
            _layoutAlgorithmTypes.Add("CompoundFDP");
            _layoutAlgorithmTypes.Add("EfficientSugiyama");
            _layoutAlgorithmTypes.Add("FR");
            _layoutAlgorithmTypes.Add("ISOM");
            _layoutAlgorithmTypes.Add("KK");
            _layoutAlgorithmTypes.Add("LinLog");
            _layoutAlgorithmTypes.Add("Tree");

            //Pick a default Layout Algorithm Type
            LayoutAlgorithmType = "Tree";
        }

        public string Text
        {
            get
            {
                return _text;
            }
            set
            {
                _text = value;
                NotifyPropertyChanged("Text");
            }
        }

        /// <summary>
        /// The actual graph
        /// </summary>
        public SuffixTreeGraph Graph 
        {
            get
            {
                return _graph;
            }
            set
            {
                _graph = value;
                NotifyPropertyChanged("Graph");
            }
        }

        /// <summary>
        /// Which layout to choose
        /// </summary>
        public List<String> LayoutAlgorithmTypes
        {
            get { return _layoutAlgorithmTypes; }
        }

        /// <summary>
        /// Which layout to use
        /// </summary>
        public string LayoutAlgorithmType
        {
            get { return _layoutAlgorithmType; }
            set
            {
                _layoutAlgorithmType = value;
                NotifyPropertyChanged("LayoutAlgorithmType");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
 
        void CreateNode(int label)
        {
            if (!_existingNodes.ContainsKey(label))
            {
                SuffixTreeNode node = new SuffixTreeNode(label);
                _graph.AddVertex(node);
                _existingNodes.Add(label, node);
            }
        }

        void CreateEdge(int source, int target, int start, int end)
        {
            SuffixTreeNode sourceNode = _existingNodes[source];
            CreateNode(target);
            SuffixTreeNode targetNode = _existingNodes[target];
            SuffixTreeEdge edge = new SuffixTreeEdge(start, end, sourceNode, targetNode);
            _graph.AddEdge(edge);
        }

        /// <summary>
        /// Creates a new QuickGraph suffix tree
        /// </summary>
        /// <param name="text"></param>
        public void CreateNewTreeView()
        {
            // clear the data structures
            Clear();
            _graph = new SuffixTreeGraph();
            // Create the actual tree
            var tree = new SuffixTree(_text);
            SuffixTreeEdge.Text = _text;
            tree.Create();

            // now walk the tree, adding edges and nodes
            tree.WalkTree(new  VisitNode(CreateNode), new VisitEdge(CreateEdge));
            this.Graph = _graph;
        }

        private void Clear()
        {
            _existingNodes.Clear();
            this.Graph = null;
        }

        void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }
}
